package com.spring.controller.work.data;

import com.alibaba.fastjson.JSONObject;
import com.spring.controller.dto.databind.User;
import com.spring.controller.dto.databind.UserList;
import com.spring.controller.dto.databind.UserMap;
import com.spring.controller.dto.databind.UserSet;
import com.util.FastJsonUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * SpringMVC笔记(3)：数据绑定
 *
 * 总结一下：
 * 1、接收数组类型的参数要使用@RequestBody方式指定参数变量，才能接收到List或Set类型的数据
 * 2、自定义类型中的pojo默认支持json和x-www-form-urlencoded两种方式
 * 3、数组参数String[]前加@RequestBody才能支持接收json参数
 *
 * <p>
 * Created by chenhs on 2018/6/21.
 */
@Controller
public class DataBindingController {


    /**
     * 区别于List接收方式，需要在参数处增加注解@RequestParam()指定一个参数名称
     * 对应例子ParamController.requestList()
     * 此处不支持application/json传参方式
     *
     * test url :
     * http://localhost:8080/databinding/arrayType.do?name=zhangsan&name=lisi&name=wangwu
     *
     * @param name
     * @return
     */
    @RequestMapping(value = "/arrayType")
    @ResponseBody
    public String arrayType(String[] name) {
        StringBuffer sb = new StringBuffer();
        for (String item : name) {
            sb.append(item).append(" ");
        }

        return "name : " + sb.toString();
    }

    /**
     * Postman使用application/json传参，如下：
     * ["China","America","Japan"]
     *
     * 看来@RequestBody是application/json请求的标配
     * POST & GET
     *
     * @param name
     * @return
     */
    @RequestMapping(value = "/arrayType2")
    @ResponseBody
    public String arrayType2(@RequestBody String[] name) {
        StringBuffer sb = new StringBuffer();
        for (String item : name) {
            sb.append(item).append(" ");
        }

        return "name : " + sb.toString();
    }

    /**
     * Postman使用application/json传参，如下：
     * ["China","America","Japan"]
     *
     * @param name
     * @return
     */
    @RequestMapping(value = "/arrayType3")
    @ResponseBody
    public String arrayType3(@RequestBody List<String> name) {
        StringBuffer sb = new StringBuffer();
        for (String item : name) {
            sb.append(item).append(" ");
        }

        return "name : " + sb.toString();
    }

    @RequestMapping
    public String prePojoType() {
        return "databind/add";
    }

    /**
     * 对比于ParamController.requestPeople()
     * Postman使用application/x-www-form-urlencoded，如：
     * name -> China
     * age  -> 12
     * address.id   ->  1
     * address.name   ->  America
     *
     * Postman使用application/json接收方式，如：
     * {"name":"张三", "age":12, "address": {"id": 1, "name":"zhangsan"}}
     *
     * @param user
     * @return
     */
    @RequestMapping(value = "pojoType")
    @ResponseBody
    public String pojoType(User user) {
        return "注册用户信息：" + user;
    }

    @RequestMapping
    public String preListType() {
        return "databind/addList";
    }

    /**
     * 此处不支持application/json传参方式，同样是自定义，pojoType可以而为什么listType就不行呢？
     * 答：我觉得可能是List需要显示系列化才行@2020-06-11
     *
     * Postman的application/x-www-form-urlencoded传参方式，如下：
     * users[0].name -> China
     * users[0].age -> 100
     * users[0].address.id -> 1
     * users[0].address.name -> Beijing
     * users[1].name -> America
     * users[1].age -> 110
     * users[1].address.id -> 2
     * users[1].address.name -> NewYork
     *
     * @param userList
     * @return
     */
    @RequestMapping(value = "listType")
    @ResponseBody
    public String listType(UserList userList) {
        StringBuffer sb = new StringBuffer();
        for (User user : userList.getUsers()) {
            sb.append(user);
        }
        return "ListType 用户 : " + sb.toString();
    }

    /**
     * 此处的@RequestBody不支持application/x-www-form-urlencoded方式传参
     * Postman使用application/json传参方式，如下：
     * {
     * 	"users": [{
     * 		"name": "China",
     * 		"age": 100,
     * 		"address": {
     * 			"id": 1,
     * 			"name": "Beigjing"
     *       }
     *   }, {
     * 		"name": "America",
     * 		"age": 110,
     * 		"address": {
     * 			"id": 2,
     * 			"name": "NewYork"
     * 		}
     * 	}]
     * }
     *
     * @param userList
     * @return
     */
    @RequestMapping(value = "listType2")
    @ResponseBody
    public String listType2(@RequestBody UserList userList) {
        StringBuffer sb = new StringBuffer();
        for (User user : userList.getUsers()) {
            sb.append(user);
        }
        return "ListType2 用户 : " + sb.toString();
    }


    @RequestMapping
    public String preSetType() {
        return "databind/addSet";
    }

    /**
     * 此处也接收不了application/json传参
     * Postman的application/x-www-form-urlencoded传参方式，如下：
     * users[0].name -> China
     * users[0].age -> 100
     * users[0].address.id -> 1
     * users[0].address.name -> Beijing
     * users[1].name -> America
     * users[1].age -> 110
     * users[1].address.id -> 2
     * users[1].address.name -> NewYork
     *
     * @param userSet
     * @return
     */
    @RequestMapping(value = "setType")
    @ResponseBody
    public String setType(UserSet userSet) {
        StringBuffer sb = new StringBuffer();
        for (User user : userSet.getUsers()) {
            sb.append(user);
        }
        return "SetType用户 : " + sb.toString();
    }

    @RequestMapping
    public String preMapType() {
        return "databind/addMap";
    }

    /**
     * 此处也接收不了application/json传参
     * Postman的application/x-www-form-urlencoded传参方式，如下：
     * users['a'].name -> China
     * users['a'].age -> 100
     * users['a'].address.id -> 1
     * users['a'].address.name -> Beijing
     * users['b'].name -> America
     * users['b'].age -> 110
     * users['b'].address.id -> 2
     * users['b'].address.name -> NewYork
     *
     * @param userMap
     * @return
     */
    @RequestMapping(value = "mapType")
    @ResponseBody
    public String setMap(UserMap userMap) {
        StringBuffer sb = new StringBuffer();
        for (String key : userMap.getUsers().keySet()) {
            User user = userMap.getUsers().get(key);
            sb.append(user);
        }
        return "MapType用户 : " + sb.toString();
    }

    /**
     * 实体中有Map
     * Postman的application/json传参方式，如下：
     * {
     * 	"users": {
     * 		"a": {
     * 			"address": {
     * 				"id": 1,
     * 				"name": "Beijing"
     *                        },
     * 			"age": 100,
     * 			"name": "China"
     * 		},
     * 		"b": {
     * 			"address": {
     * 				"id": 2,
     * 				"name": "NewYork"
     *            },
     * 			"age": 110,
     * 			"name": "America"
     *        }
     *    }
     * }
     *
     * @param userMap
     * @return
     */
    @RequestMapping(value = "mapType2")
    @ResponseBody
    public String setMap2(@RequestBody UserMap userMap) {
        StringBuffer sb = new StringBuffer();
        for (String key : userMap.getUsers().keySet()) {
            User user = userMap.getUsers().get(key);
            sb.append(user);
        }
        return "MapType用户 : " + sb.toString();
    }

    /**
     * 纯Map方式接收参数，支持application/json，如下：
     * {
     * 	"a": {
     * 		"address": {
     * 			"id": 1,
     * 			"name": "Beijing"
     *                },
     * 		"age": 100,
     * 		"name": "China"
     * 	},
     * 	"b": {
     * 		"address": {
     * 			"id": 2,
     * 			"name": "NewYork"
     * 		}        ,
     * 		"age": 110,
     * 		"name": "America"
     *    }
     * }
     *
     *  这里的key-value接收json参数的过程，value得到的是一个java.util.LinkedHashMap类型的值
     *  所以这里用什么对象接收都可以（User或Object）结果都一样。要想得到最终的结果值建议使用
     *  json2obj方式去转换
     *
     * @param users
     * @return
     */
    @RequestMapping(value = "mapType3")
    @ResponseBody
    public String setMap3(@RequestBody HashMap<String, User> users) {
        StringBuffer sb = new StringBuffer();
        for (String key : users.keySet()) {
            System.out.println(key);
            System.out.println(users.get(key));
            User u = FastJsonUtils.json2obj(FastJsonUtils.obj2json(users.get(key)), User.class);
            sb.append(u);
        }
        return "MapType用户 : " + sb.toString();
    }

    /**
     * 纯Map方式接收参数，支持application/json，如下：
     * {
     * 	"a": {
     * 		"address": {
     * 			"id": 1,
     * 			"name": "Beijing"
     *                },
     * 		"age": 100,
     * 		"name": "China"
     * 	 },
     * 	"b": {
     * 		"address": {
     * 			"id": 2,
     * 			"name": "NewYork"
     * 		}        ,
     * 		"age": 110,
     * 		"name": "America"
     *    }
     * }
     *
     * 这里的key-value接收json参数的过程，value得到的是一个java.util.LinkedHashMap类型的值
     * 所以这里用什么对象接收都可以（User或Object）结果都一样。要想得到最终的结果值建议使用
     * json2obj方式去转换
     *
     * 其实我觉得它的使用场景应该是，当我不想专门创建一个pojo接收这些json时，可以使用以下map
     * 接收方式。它可任意转换。
     *
     * @param users
     * @return
     */
    @RequestMapping(value = "mapType4")
    @ResponseBody
    public String setMap4(@RequestBody HashMap<String, Object> users) {
        //JSONObject jsonObject = new JSONObject(users);
        StringBuffer sb = new StringBuffer();
        /**
         * 此处打印"Beijing"
         * 我明白了，传过来的json字符体，使用Map接收后它以key-value嵌套的方式存储
         * 所以还是以<String,Object>方式接收最好了，其实这里的Object就是一个java.util.LinkedHashMap类型的对象
         */
        System.out.println(((Map)((Map)users.get("a")).get("address")).get("name").toString());

        for (String key : users.keySet()) {
            sb.append(users.get(key));
        }
        return "MapType用户 : " + sb.toString();
    }

    /**
     * 使用add.jsp页面
     * @param user
     * @return
     */
    @RequestMapping(value = "jsonType")
    @ResponseBody
    public User jsonType(@RequestBody User user) {
        //修改年龄
        user.setAge(80);
        //返回前端
        return user;
    }

}
